home *** CD-ROM | disk | FTP | other *** search
- /* Application programming interface routines - based loosely on the
- * "socket" model in Berkeley UNIX.
- *
- * Copyright 1991 Phil Karn, KA9Q
- */
- #include "global.h"
- #include <time.h>
- #ifndef MSDOS
- #include <stdarg.h>
- #endif
- #include "mbuf.h"
- #include "netuser.h"
- #include "iface.h"
- #include "udp.h"
- #include "netrom.h"
- #include "lzw.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: socket.c,v 1.24 1997/08/19 01:19:22 root Exp root $";
- #endif
-
- /* In connect(), accept() and recv_mbuf()
- * the noblock options have been removed, since they never occur anyway.
- * If you want then back, do a '#define useblock 1'
- * The socket's 'noblock' parameter is now only effective for sending
- * data; ie if set, only sending data will not block. - WG7J
- */
- #define useblock 1
-
-
- static void autobind (int s, int af);
- static int checkaddr (int type, char *name, int namelen);
- static void rip_recv (struct raw_ip * rp);
- static void s_trcall (struct tcb * tcb, int16 cnt);
- static void s_tscall (struct tcb * tcb, int old, int new);
- static void s_ttcall (struct tcb * tcb, int16 cnt);
- static void s_urcall (struct iface * iface, struct udp_cb * udp, int16 cnt);
- static void trdiscard (struct tcb * tcb, int16 cnt);
-
- #ifdef NETROM
- static void s_nrcall (struct nr4cb * cb, int16 cnt);
- static void s_nscall (struct nr4cb * cb, int old, int new);
- static void s_ntcall (struct nr4cb * cb, int16 cnt);
- #endif
-
- static int16 Lport = 1024;
-
- const char *Socktypes[] =
- {
- "Not Used",
- "TCP",
- "UDP",
- "AX25 I",
- "AX25 UI",
- "Raw IP",
- "NETROM3",
- "NETROM",
- "Loc St",
- "Loc Dg"
- };
-
-
- char Badsocket[] = "Bad socket";
- struct usock *Usock; /* Socket entry array */
- int Nusock = DEFNSOCK; /* Number of socket entries */
-
- /* The following two variables are needed because there can be only one
- * socket listening on each of the AX.25 modes (I and UI)
- */
- #ifdef AX25
- int Axi_sock = -1; /* Socket number listening for AX25 connections */
-
- #if 0
- int Axui_sock = -1; /* Socket number listening for AX25 UI frames */
- static struct mbuf *Bcq; /* Queue of incoming UI frames */
-
- /* Function that handles incoming UI frames from lapb.c */
- void
- beac_input (struct iface *iface, char *src, struct mbuf *bp)
- {
- struct mbuf *hdr;
- struct sockaddr_ax *sax;
-
- if (Axui_sock == -1) /* Nobody there to read it */
- free_p (bp);
- else {
- if ((hdr = pushdown (NULLBUF, sizeof (struct sockaddr_ax))) == NULLBUF) {
- free_p (bp);
- return;
- }
- sax = (struct sockaddr_ax *) hdr->data;
- sax->sax_family = AF_AX25;
- memcpy (sax->ax25_addr, src, AXALEN);
- strncpy (sax->iface, iface->name, ILEN - 1);
- hdr->next = bp;
- enqueue (&Bcq, hdr);
- }
- }
- #endif
- #endif /* AX.25 */
-
-
-
- /* Initialize user socket array */
- void
- sockinit (void)
- {
- if (Usock != NULLUSOCK)
- return; /* Already initialized */
- Usock = (struct usock *) callocw ((unsigned) Nusock, sizeof (struct usock));
- }
-
-
-
- /* Create a user socket, return socket index
- * The mapping to actual protocols is as follows:
- *
- *
- * ADDRESS FAMILY Stream Datagram Raw Seq. Packet
- *
- * AF_INET TCP UDP IP
- * AF_AX25 I-frames UI-frames
- * AF_NETROM NET/ROM L3 NET/ROM L4
- * AF_LOCAL stream loopback packet loopback
- */
- int
- socket (
- int af, /* Address family */
- int type, /* Stream or datagram */
- int protocol /* Used for raw IP sockets */
- ) {
- register struct usock *up;
- int s;
-
- for (up = Usock; up < &Usock[Nusock]; up++)
- if (up->type == NOTUSED)
- break;
-
- if (up == &Usock[Nusock]) {
- /* None left */
- errno = EMFILE;
- return -1;
- }
- /* set the time the socket was created - WG7J */
- up->created = time (NULL);
- up->refcnt = 1;
- s = up - Usock + SOCKBASE;
- errno = 0;
- up->look = NULLPROC;
- up->noblock = SOCK_BLOCK;
- up->rdysock = -1;
- up->cb.p = NULLCHAR;
- up->peername = up->name = NULLCHAR;
- up->namelen = up->peernamelen = 0;
- up->owner = Curproc;
- up->obuf = NULLBUF;
- up->insertbuf = NULLCHAR;
- up->insertptr = NULLCHAR;
- memset (up->errcodes, 0, sizeof (up->errcodes));
- memset (up->eol, 0, sizeof (up->eol));
- up->flush = '\n'; /* default is line buffered */
- switch (af) {
- case AF_LOCAL:
- up->cb.local = (struct loc *) callocw (1, sizeof (struct loc));
-
- up->cb.local->peer = up; /* connect to self */
- switch (type) {
- case SOCK_STREAM:
- up->type = TYPE_LOCAL_STREAM;
- up->cb.local->hiwat = LOCSFLOW;
- break;
- case SOCK_DGRAM:
- up->type = TYPE_LOCAL_DGRAM;
- up->cb.local->hiwat = LOCDFLOW;
- break;
- default:
- free (up->cb.local);
- errno = ESOCKTNOSUPPORT;
- break;
- }
- break;
- #ifdef AX25
- case AF_AX25:
- switch (type) {
- case SOCK_STREAM:
- up->type = TYPE_AX25I;
- break;
- case SOCK_DGRAM:
- up->type = TYPE_AX25UI;
- break;
- default:
- errno = ESOCKTNOSUPPORT;
- break;
- }
- strcpy (up->eol, AX_EOL);
- break;
- #endif
- #ifdef NETROM
- case AF_NETROM:
- switch (type) {
- case SOCK_RAW:
- up->type = TYPE_NETROML3;
- up->cb.rnr = raw_nr ((char) protocol);
- break;
- case SOCK_SEQPACKET:
- up->type = TYPE_NETROML4;
- break;
- default:
- errno = ESOCKTNOSUPPORT;
- break;
- }
- strcpy (up->eol, AX_EOL);
- break;
- #endif
- case AF_INET:
- switch (type) {
- case SOCK_STREAM:
- up->type = TYPE_TCP;
- strcpy (up->eol, INET_EOL);
- break;
- case SOCK_DGRAM:
- up->type = TYPE_UDP;
- break;
- case SOCK_RAW:
- up->type = TYPE_RAW;
- up->cb.rip = raw_ip (protocol, rip_recv);
- up->cb.rip->user = s;
- break;
- default:
- errno = ESOCKTNOSUPPORT;
- break;
- }
- break;
- default:
- errno = EAFNOSUPPORT;
- break;
- }
- if (errno)
- return -1;
-
- return s;
- }
-
-
-
- /* Attach a local address/port to a socket. If not issued before a connect
- * or listen, will be issued automatically
- */
- int
- bind (
- int s, /* Socket index */
- char *name, /* Local name */
- int namelen /* Length of name */
- ) {
- register struct usock *up;
- union sp local;
- struct socket lsock;
-
- if ((up = itop (s)) == NULLUSOCK) {
- errno = EBADF;
- return -1;
- }
- if (up->type == TYPE_LOCAL_STREAM || up->type == TYPE_LOCAL_DGRAM) {
- errno = EINVAL;
- return -1;
- }
- if (name == NULLCHAR) {
- errno = EFAULT;
- return -1;
- }
- if (up->name != NULLCHAR) {
- /* Bind has already been issued */
- errno = EINVAL;
- return -1;
- }
- if (checkaddr (up->type, name, namelen) == -1) {
- /* Incorrect length or family for chosen protocol */
- errno = EAFNOSUPPORT;
- return -1;
- }
- /* Stash name in an allocated block */
- up->namelen = namelen;
- up->name = mallocw ((unsigned) namelen);
- memcpy (up->name, name, (size_t) namelen);
- /* Create control block for datagram sockets */
- switch (up->type) {
- case TYPE_UDP:
- local.in = (struct sockaddr_in *) up->name;
- lsock.address = local.in->sin_addr.s_addr;
- lsock.port = local.in->sin_port;
- if ((up->cb.udp = open_udp (&lsock, s_urcall)) != NULLUDP)
- up->cb.udp->user = s;
- else
- return -1;
- break;
- #ifdef notdef
- case TYPE_AX25UI:
- if (Axui_sock != -1) {
- errno = EADDRINUSE;
- return -1;
- }
- Axui_sock = s;
- break;
- #endif
- default:
- break;
- }
- return 0;
- }
-
-
-
- /* Post a listen on a socket */
- int
- listen (
- int s, /* Socket index */
- int backlog /* 0 for a single connection, 1 for multiple connections */
- ) {
- register struct usock *up;
- union sp local;
- struct socket lsock;
-
- if ((up = itop (s)) == NULLUSOCK) {
- errno = EBADF;
- return -1;
- }
- if (up->type == TYPE_LOCAL_STREAM || up->type == TYPE_LOCAL_DGRAM) {
- errno = EINVAL;
- return -1;
- }
- if (up->cb.p != NULLCHAR) {
- errno = EISCONN;
- return -1;
- }
- switch (up->type) {
- case TYPE_TCP:
- if (up->name == NULLCHAR)
- autobind (s, AF_INET);
-
- local.in = (struct sockaddr_in *) up->name;
- lsock.address = local.in->sin_addr.s_addr;
- lsock.port = local.in->sin_port;
- up->cb.tcb = open_tcp (&lsock, NULLSOCK,
- backlog ? TCP_SERVER : TCP_PASSIVE, 0,
- s_trcall, s_ttcall, s_tscall, 0, s);
- break;
- #ifdef AX25
- case TYPE_AX25I:
- if (up->name == NULLCHAR)
- autobind (s, AF_AX25);
- if (s != Axi_sock) {
- errno = EOPNOTSUPP;
- return -1;
- }
- local.ax = (struct sockaddr_ax *) up->name;
- up->cb.ax25 = open_ax25 (NULLIF, local.ax->ax25_addr, NULLCHAR,
- backlog ? AX_SERVER : AX_PASSIVE, 0,
- s_arcall, s_atcall, s_ascall, s);
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML4:
- if (up->name == NULLCHAR)
- autobind (s, AF_NETROM);
- local.nr = (struct sockaddr_nr *) up->name;
- up->cb.nr4 = open_nr4 (&local.nr->nr_addr, NULLNRADDR,
- backlog ? AX_SERVER : AX_PASSIVE,
- s_nrcall, s_ntcall, s_nscall, s);
- break;
- #endif
- default:
- /* Listen not supported on datagram sockets */
- errno = EOPNOTSUPP;
- return -1;
- }
- return 0;
- }
-
-
-
- /* Initiate active open. For datagram sockets, merely bind the remote address. */
- int
- connect (
- int s, /* Socket index */
- char *peername, /* Peer name */
- int peernamelen /* Length of peer name */
- ) {
- register struct usock *up;
- union cb cb;
- union sp local, remote;
- struct socket lsock, fsock;
- #ifdef AX25
- struct iface *iface;
- #endif
-
- if ((up = itop (s)) == NULLUSOCK) {
- errno = EBADF;
- return -1;
- }
- if (up->type == TYPE_LOCAL_DGRAM || up->type == TYPE_LOCAL_STREAM) {
- errno = EINVAL;
- return -1;
- }
- if (peername == NULLCHAR) {
- /* Connect must specify a remote address */
- errno = EFAULT;
- return -1;
- }
- if (checkaddr (up->type, peername, peernamelen) == -1) {
- errno = EAFNOSUPPORT;
- return -1;
- }
- /* Raw socket control blocks are created in socket() */
- if (up->type != TYPE_RAW && up->type != TYPE_NETROML3 &&
- up->cb.p != NULLCHAR) {
- errno = EISCONN;
- return -1;
- }
- up->peername = mallocw ((unsigned) peernamelen);
- memcpy (up->peername, peername, (size_t) peernamelen);
- up->peernamelen = peernamelen;
-
- /* Set up the local socket structures */
- if (up->name == NULLCHAR) {
- switch (up->type) {
- case TYPE_TCP:
- case TYPE_UDP:
- case TYPE_RAW:
- autobind (s, AF_INET);
- break;
- #ifdef AX25
- case TYPE_AX25I:
- case TYPE_AX25UI:
- autobind (s, AF_AX25);
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- case TYPE_NETROML4:
- autobind (s, AF_NETROM);
- break;
- #endif
- default:
- break;
- }
- }
- switch (up->type) {
- case TYPE_TCP:
- /* Construct the TCP-style ports from the sockaddr structs */
- local.in = (struct sockaddr_in *) up->name;
- remote.in = (struct sockaddr_in *) up->peername;
-
- if (local.in->sin_addr.s_addr == INADDR_ANY)
- /* Choose a local address */
- local.in->sin_addr.s_addr = locaddr (remote.in->sin_addr.s_addr);
-
- lsock.address = local.in->sin_addr.s_addr;
- lsock.port = local.in->sin_port;
- fsock.address = remote.in->sin_addr.s_addr;
- fsock.port = remote.in->sin_port;
-
- /* Open the TCB in active mode */
- up->cb.tcb = open_tcp (&lsock, &fsock, TCP_ACTIVE, 0,
- s_trcall, s_ttcall, s_tscall, 0, s);
-
- /* Wait for the connection to complete */
- while ((cb.tcb = up->cb.tcb) != NULLTCB && cb.tcb->state != TCP_ESTABLISHED) {
- #ifdef useblock
- if (up->noblock) {
- errno = EWOULDBLOCK;
- return -1;
- } else
- #endif
- if ((errno = kwait (up)) != 0)
- return -1;
- }
- if (cb.tcb == NULLTCB) {
- /* Probably got refused */
- free (up->peername);
- up->peername = NULLCHAR;
- errno = ECONNREFUSED;
- return -1;
- }
- break;
- case TYPE_UDP:
- #ifdef AX25
- case TYPE_AX25UI:
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- #endif
- case TYPE_RAW:
- /* Control block already created by bind() */
- break;
- #ifdef AX25
- case TYPE_AX25I:
- local.ax = (struct sockaddr_ax *) up->name;
- remote.ax = (struct sockaddr_ax *) up->peername;
- if ((iface = if_lookup (remote.ax->iface)) == NULLIF) {
- errno = EINVAL;
- return -1;
- }
- if (local.ax->ax25_addr[0] == '\0') {
- /* The local address was unspecified; set it from
- * the interface address
- */
- memcpy (local.ax->ax25_addr, iface->hwaddr, AXALEN);
- }
- /* If we already have an AX25 link we can use it */
- if ((up->cb.ax25 = find_ax25 (local.ax->ax25_addr,
- remote.ax->ax25_addr, iface)) != NULLAX25
- && up->cb.ax25->state != LAPB_DISCONNECTED &&
- up->cb.ax25->user == -1) {
- up->cb.ax25->user = s;
- up->cb.ax25->r_upcall = s_arcall;
- up->cb.ax25->t_upcall = s_atcall;
- up->cb.ax25->s_upcall = s_ascall;
- if (up->cb.ax25->state == LAPB_CONNECTED
- || up->cb.ax25->state == LAPB_RECOVERY)
- return 0;
- } else
- up->cb.ax25 = open_ax25 (iface, local.ax->ax25_addr,
- remote.ax->ax25_addr, AX_ACTIVE,
- Axwindow, s_arcall, s_atcall, s_ascall, s);
-
- /* Wait for the connection to complete */
- while ((cb.ax25 = up->cb.ax25) != NULLAX25 && cb.ax25->state != LAPB_CONNECTED) {
- #ifdef useblock
- if (up->noblock) {
- errno = EWOULDBLOCK;
- return -1;
- } else
- #endif
- if ((errno = kwait (up)) != 0)
- return -1;
- }
- if (cb.ax25 == NULLAX25) {
- /* Connection probably already exists */
- free (up->peername);
- up->peername = NULLCHAR;
- errno = ECONNREFUSED;
- return -1;
- }
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML4:
- local.nr = (struct sockaddr_nr *) up->name;
- remote.nr = (struct sockaddr_nr *) up->peername;
- up->cb.nr4 = open_nr4 (&local.nr->nr_addr, &remote.nr->nr_addr,
- AX_ACTIVE, s_nrcall, s_ntcall, s_nscall, s);
-
- /* Wait for the connection to complete */
- while ((cb.nr4 = up->cb.nr4) != NULLNR4CB && cb.nr4->state != NR4STCON) {
- #ifdef useblock
- if (up->noblock) {
- errno = EWOULDBLOCK;
- return -1;
- } else
- #endif
- if ((errno = kwait (up)) != 0)
- return -1;
- }
- if (cb.nr4 == NULLNR4CB) {
- /* Connection probably already exists */
- free (up->peername);
- up->peername = NULLCHAR;
- errno = ECONNREFUSED;
- return -1;
- }
- break;
- #endif
- default:
- break;
- }
- return 0;
- }
-
-
-
- /* Wait for a connection. Valid only for connection-oriented sockets. */
- int
- accept (
- int s, /* Socket index */
- char *peername, /* Peer name */
- int *peernamelen /* Length of peer name */
- ) {
- int i;
- register struct usock *up;
-
- if ((up = itop (s)) == NULLUSOCK) {
- errno = EBADF;
- return -1;
- }
- if (up->type == TYPE_LOCAL_DGRAM || up->type == TYPE_LOCAL_STREAM) {
- errno = EINVAL;
- return -1;
- }
- if (up->cb.p == NULLCHAR) {
- errno = EOPNOTSUPP;
- return -1;
- }
- /* Accept is valid only for stream sockets */
- switch (up->type) {
- case TYPE_TCP:
- #ifdef AX25
- case TYPE_AX25I:
- #endif
- #ifdef NETROM
- case TYPE_NETROML4:
- #endif
- break;
- default:
- errno = EOPNOTSUPP;
- return -1;
- }
- /* Wait for the state-change upcall routine to signal us */
- while (up->cb.p != NULLCHAR && up->rdysock == -1) {
- #ifdef useblock
- if (up->noblock) {
- errno = EWOULDBLOCK;
- return -1;
- } else
- #endif
- if ((errno = kwait (up)) != 0)
- return -1;
- }
- if (up->cb.p == NULLCHAR) {
- /* Blown away */
- errno = EBADF;
- return -1;
- }
- i = up->rdysock;
- up->rdysock = -1;
-
- up = itop (i);
- if (peername != NULLCHAR && peernamelen != NULL) {
- *peernamelen = min (up->peernamelen, *peernamelen);
- memcpy (peername, up->peername, (size_t) * peernamelen);
- }
- /* set the time this was created - WG7J */
- if (up == NULLUSOCK) {
- errno = EBADF;
- return -1;
- }
- up->created = time (NULL);
- return i;
- }
-
-
-
- /* Low-level receive routine. Passes mbuf back to user; more efficient than
- * higher-level functions recv() and recvfrom(). Datagram sockets ignore
- * the len parameter.
- */
- int
- recv_mbuf (
- int s, /* Socket index */
- struct mbuf **bpp, /* Place to stash receive buffer */
- int flags OPTIONAL, /* Unused; will control out-of-band data, etc */
- char *from, /* Peer address (only for datagrams) */
- int *fromlen /* Length of peer address */
- ) {
- register struct usock *up;
- int cnt = 0;
- union cb cb;
- struct socket fsocket;
- union sp remote;
- struct ip ip;
- struct mbuf *bp = NULLBUF;
- #ifdef NETROM
- struct nr3hdr n3hdr;
- #endif
-
- if ((up = itop (s)) == NULLUSOCK) {
- errno = EBADF;
- return -1;
- }
- if (up->ibuf != NULLBUF) {
- /* Return input buffer */
- cnt = len_p (up->ibuf);
- if (bpp != NULLBUFP)
- *bpp = up->ibuf;
- else
- free_p (up->ibuf);
- up->ibuf = NULLBUF;
- return cnt;
- }
- switch (up->type) {
- case TYPE_LOCAL_STREAM:
- case TYPE_LOCAL_DGRAM:
- while (up->cb.local != NULLLOC && up->cb.local->q == NULLBUF
- && up->cb.local->peer != NULLUSOCK) {
- #ifdef useblock
- if (up->noblock & SOCK_NORXBLOCK) {
- errno = (Curproc->retval == EALARM) ? EALARM : EWOULDBLOCK;
- return -1;
- } else
- #endif
- if ((errno = kwait (up)) != 0)
- return -1;
- }
- if (up->cb.local == NULLLOC) {
- errno = EBADF;
- return -1;
- }
- if (up->cb.local->q == NULLBUF && up->cb.local->peer == NULLUSOCK) {
- errno = ENOTCONN;
- return -1;
- }
- /* For datagram sockets, this will return the
- * first packet on the queue. For stream sockets,
- * this will return everything.
- */
- bp = dequeue (&up->cb.local->q);
- if (up->cb.local->q == NULLBUF && (up->cb.local->flags & LOC_SHUTDOWN))
- close_s (s);
- ksignal (up, 0);
- cnt = len_p (bp);
- break;
- case TYPE_TCP:
- while ((cb.tcb = up->cb.tcb) != NULLTCB
- && cb.tcb->r_upcall != trdiscard
- && (cnt = recv_tcp (cb.tcb, &bp, (int16) 0)) == -1) {
- #ifdef useblock
- if (up->noblock & SOCK_NORXBLOCK) {
- errno = (Curproc->retval == EALARM) ? EALARM : EWOULDBLOCK;
- return -1;
- } else
- #endif
- if ((errno = kwait (up)) != 0)
- return -1;
- }
- if (cb.tcb == NULLTCB) {
- /* Connection went away */
- errno = ENOTCONN;
- return -1;
- } else if (cb.tcb->r_upcall == trdiscard) {
- /* Receive shutdown has been done */
- errno = ENOTCONN; /* CHANGE */
- return -1;
- }
- break;
- case TYPE_UDP:
- while ((cb.udp = up->cb.udp) != NULLUDP && (cnt = recv_udp (cb.udp, &fsocket, &bp)) == -1) {
- #ifdef useblock
- if (up->noblock & SOCK_NORXBLOCK) {
- errno = (Curproc->retval == EALARM) ? EALARM : EWOULDBLOCK;
- return -1;
- } else
- #endif
- if ((errno = kwait (up)) != 0)
- return -1;
- }
- if (cb.udp == NULLUDP) {
- /* Connection went away */
- errno = ENOTCONN;
- return -1;
- }
- if (from != NULLCHAR && fromlen != (int *) NULL && *fromlen >= (int) SOCKSIZE) {
- remote.in = (struct sockaddr_in *) from;
- remote.in->sin_family = AF_INET;
- remote.in->sin_addr.s_addr = fsocket.address;
- remote.in->sin_port = fsocket.port;
- *fromlen = SOCKSIZE;
- }
- break;
- case TYPE_RAW:
- while ((cb.rip = up->cb.rip) != NULLRIP && cb.rip->rcvq == NULLBUF) {
- #ifdef useblock
- if (up->noblock & SOCK_NORXBLOCK) {
- errno = (Curproc->retval == EALARM) ? EALARM : EWOULDBLOCK;
- return -1;
- } else
- #endif
- if ((errno = kwait (up)) != 0)
- return -1;
- }
- if (cb.rip == NULLRIP) {
- /* Connection went away */
- errno = ENOTCONN;
- return -1;
- }
- bp = dequeue (&cb.rip->rcvq);
- (void) ntohip (&ip, &bp);
-
- cnt = len_p (bp);
- if (from != NULLCHAR && fromlen != (int *) NULL && *fromlen >= (int) SOCKSIZE) {
- remote.in = (struct sockaddr_in *) from;
- remote.in->sin_family = AF_INET;
- remote.in->sin_addr.s_addr = ip.source;
- remote.in->sin_port = 0;
- *fromlen = SOCKSIZE;
- }
- break;
- #ifdef AX25
- case TYPE_AX25I:
- while ((cb.ax25 = up->cb.ax25) != NULLAX25 && (bp = recv_ax25 (cb.ax25, (int16) 0)) == NULLBUF) {
- #ifdef useblock
- if (up->noblock & SOCK_NORXBLOCK) {
- errno = (Curproc->retval == EALARM) ? EALARM : EWOULDBLOCK;
- return -1;
- } else
- #endif
- if ((errno = kwait (up)) != 0)
- return -1;
- }
- if (cb.ax25 == NULLAX25) {
- /* Connection went away */
- errno = ENOTCONN;
- return -1;
- }
- if (bp == NULLBUF)
- return 0;
- cnt = bp->cnt;
- break;
- #ifdef notdef
- case TYPE_AX25UI:
- while (s == Axui_sock && Bcq == NULLBUF) {
- #ifdef useblock
- if (up->noblock & SOCK_NORXBLOCK) {
- errno = (Curproc->retval == EALARM) ? EALARM : EWOULDBLOCK;
- return -1;
- } else
- #endif
- if ((errno = kwait (&Bcq)) != 0)
- return -1;
- }
- if (s != Axui_sock) {
- errno = ENOTCONN;
- return -1;
- }
- bp = dequeue (&Bcq);
-
- if (from != NULLCHAR && fromlen != NULLINT
- && *fromlen >= sizeof (struct sockaddr_ax)) {
- pullup (&bp, from, sizeof (struct sockaddr_ax));
- *fromlen = sizeof (struct sockaddr_ax);
- } else
- pullup (&bp, NULLCHAR, sizeof (struct sockaddr_ax));
-
- cnt = len_p (bp);
- break;
- #endif /* notdef */
- #endif /* ax25 */
- #ifdef NETROM
- case TYPE_NETROML3:
- while ((cb.rnr = up->cb.rnr) != NULLRNR && cb.rnr->rcvq == NULLBUF) {
- #ifdef useblock
- if (up->noblock & SOCK_NORXBLOCK) {
- errno = (Curproc->retval == EALARM) ? EALARM : EWOULDBLOCK;
- return -1;
- } else
- #endif
- if ((errno = kwait (up)) != 0)
- return -1;
- }
- if (cb.rnr == NULLRNR) {
- /* Connection went away */
- errno = ENOTCONN;
- return -1;
- }
- bp = dequeue (&cb.rnr->rcvq);
- (void) ntohnr3 (&n3hdr, &bp);
- cnt = len_p (bp);
- if (from != NULLCHAR && fromlen != NULLINT
- && *fromlen >= (int) sizeof (struct sockaddr_nr)) {
- remote.nr = (struct sockaddr_nr *) from;
- remote.nr->nr_family = AF_NETROM;
- /* The callsign of the local user is not part of
- NET/ROM level 3, so that field is not used here */
- memcpy (remote.nr->nr_addr.node, n3hdr.source, AXALEN);
- *fromlen = sizeof (struct sockaddr_nr);
- }
- break;
- case TYPE_NETROML4:
- while ((cb.nr4 = up->cb.nr4) != NULLNR4CB && (bp = recv_nr4 (cb.nr4, (int16) 0)) == NULLBUF) {
- #ifdef useblock
- if (up->noblock & SOCK_NORXBLOCK) {
- errno = (Curproc->retval == EALARM) ? EALARM : EWOULDBLOCK;
- return -1;
- } else
- #endif
- if ((errno = kwait (up)) != 0)
- return -1;
- }
- if (cb.nr4 == NULLNR4CB) {
- /* Connection went away */
- errno = ENOTCONN;
- return -1;
- }
- if (bp == NULLBUF)
- return 0;
- cnt = bp->cnt;
- break;
- #endif
- default:
- break;
- }
- if (bpp != NULLBUFP)
- *bpp = bp;
- else
- free_p (bp);
- return cnt;
- }
-
-
-
- /* Low level send routine; user supplies mbuf for transmission. More
- * efficient than send() or sendto(), the higher level interfaces.
- * The "to" and "tolen" parameters are ignored on connection-oriented
- * sockets.
- *
- * In case of error, bp is freed so the caller doesn't have to worry about it.
- */
- int
- send_mbuf (
- int s, /* Socket index */
- struct mbuf *bp, /* Buffer to send */
- int flags, /* not currently used */
- char *to, /* Destination, only for datagrams */
- int tolen /* Length of destination */
- ) {
- register struct usock *up;
- union cb cb;
- union sp local, remote;
- struct socket lsock, fsock;
- int cnt;
-
- if ((up = itop (s)) == NULLUSOCK) {
- free_p (bp);
- errno = EBADF;
- return -1;
- }
- #ifndef notdef
- if (up->obuf != NULLBUF) {
- /* If there's unflushed output, send it.
- * Note the importance of clearing up->obuf
- * before the recursive call!
- */
- struct mbuf *bp1;
-
- bp1 = up->obuf;
- up->obuf = NULLBUF;
- (void) send_mbuf (s, bp1, flags, to, tolen);
- }
- #endif
- if (up->name == NULLCHAR) {
- /* Automatic local name assignment for datagram sockets */
- switch (up->type) {
- case TYPE_LOCAL_STREAM:
- case TYPE_LOCAL_DGRAM:
- break; /* no op */
- case TYPE_UDP:
- case TYPE_RAW:
- autobind (s, AF_INET);
- break;
- #ifdef AX25
- case TYPE_AX25UI:
- autobind (s, AF_AX25);
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- case TYPE_NETROML4:
- autobind (s, AF_NETROM);
- break;
- #endif
- default:
- free_p (bp);
- errno = ENOTCONN;
- return -1;
- }
- }
- cnt = len_p (bp);
- switch (up->type) {
- case TYPE_LOCAL_DGRAM:
- if (up->cb.local->peer == NULLUSOCK) {
- free_p (bp);
- errno = ENOTCONN;
- return -1;
- }
- enqueue (&up->cb.local->peer->cb.local->q, bp);
- ksignal (up->cb.local->peer, 0);
- /* If high water mark has been reached, block */
- while (up->cb.local->peer != NULLUSOCK &&
- len_q (up->cb.local->peer->cb.local->q) >=
- up->cb.local->peer->cb.local->hiwat) {
- if (up->noblock & SOCK_NOTXBLOCK) {
- errno = EWOULDBLOCK;
- return -1;
- } else if ((errno = kwait (up->cb.local->peer)) != 0) {
- return -1;
- }
- }
- if (up->cb.local->peer == NULLUSOCK) {
- errno = ENOTCONN;
- return -1;
- }
- break;
- case TYPE_LOCAL_STREAM:
- if (up->cb.local->peer == NULLUSOCK) {
- free_p (bp);
- errno = ENOTCONN;
- return -1;
- }
- append (&up->cb.local->peer->cb.local->q, bp);
- ksignal (up->cb.local->peer, 0);
- /* If high water mark has been reached, block */
- while (up->cb.local->peer != NULLUSOCK &&
- len_p (up->cb.local->peer->cb.local->q) >=
- up->cb.local->peer->cb.local->hiwat) {
- if (up->noblock & SOCK_NOTXBLOCK) {
- errno = EWOULDBLOCK;
- return -1;
- } else if ((errno = kwait (up->cb.local->peer)) != 0) {
- return -1;
- }
- }
- if (up->cb.local->peer == NULLUSOCK) {
- errno = ENOTCONN;
- return -1;
- }
- break;
- case TYPE_TCP:
- if ((cb.tcb = up->cb.tcb) == NULLTCB) {
- free_p (bp);
- errno = ENOTCONN;
- return -1;
- }
- cnt = send_tcp (cb.tcb, bp);
-
- while ((cb.tcb = up->cb.tcb) != NULLTCB &&
- cb.tcb->sndcnt > cb.tcb->window) {
- /* Send queue is full */
- if (up->noblock & SOCK_NOTXBLOCK) {
- errno = EWOULDBLOCK;
- return -1;
- } else if ((errno = kwait (up)) != 0) {
- return -1;
- }
- }
- if (cb.tcb == NULLTCB) {
- errno = ENOTCONN;
- return -1;
- }
- break;
- case TYPE_UDP:
- local.in = (struct sockaddr_in *) up->name;
- lsock.address = local.in->sin_addr.s_addr;
- lsock.port = local.in->sin_port;
- if (to != NULLCHAR)
- remote.in = (struct sockaddr_in *) to;
- else if (up->peername != NULLCHAR)
- remote.in = (struct sockaddr_in *) up->peername;
- else {
- errno = ENOTCONN;
- return -1;
- }
- fsock.address = remote.in->sin_addr.s_addr;
- fsock.port = remote.in->sin_port;
- (void) send_udp (&lsock, &fsock, 0, 0, bp, 0, 0, 0);
- break;
- case TYPE_RAW:
- local.in = (struct sockaddr_in *) up->name;
- if (to != NULLCHAR)
- remote.in = (struct sockaddr_in *) to;
- else if (up->peername != NULLCHAR)
- remote.in = (struct sockaddr_in *) up->peername;
- else {
- errno = ENOTCONN;
- return -1;
- }
- (void) ip_send (local.in->sin_addr.s_addr, remote.in->sin_addr.s_addr,
- (char) up->cb.rip->protocol, 0, 0, bp, 0, 0, 0);
- break;
- #ifdef AX25
- case TYPE_AX25I:
- if ((cb.ax25 = up->cb.ax25) == NULLAX25) {
- free_p (bp);
- errno = ENOTCONN;
- return -1;
- }
- (void) send_ax25 (cb.ax25, bp, PID_NO_L3);
-
- while ((cb.ax25 = up->cb.ax25) != NULLAX25 &&
- len_q (cb.ax25->txq) * cb.ax25->paclen > cb.ax25->window) {
- if (up->noblock & SOCK_NOTXBLOCK) {
- errno = EWOULDBLOCK;
- return -1;
- } else if ((errno = kwait (up)) != 0) {
- return -1;
- }
- }
- if (cb.ax25 == NULLAX25) {
- errno = EBADF;
- return -1;
- }
- break;
- case TYPE_AX25UI:
- local.ax = (struct sockaddr_ax *) up->name;
- if (to != NULLCHAR)
- remote.ax = (struct sockaddr_ax *) to;
- else if (up->peername != NULLCHAR)
- remote.ax = (struct sockaddr_ax *) up->peername;
- else {
- errno = ENOTCONN;
- return -1;
- }
- (void) ax_output (if_lookup (remote.ax->iface), remote.ax->ax25_addr,
- local.ax->ax25_addr, PID_NO_L3, bp);
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- /* This should never happen, since the TCP code will peek at the
- * interface mtu ! - WG7J
- */
- if (len_p (bp) > NR4MAXINFO) {
- free_p (bp);
- errno = EMSGSIZE;
- return -1;
- }
- local.nr = (struct sockaddr_nr *) up->name;
- if (to != NULLCHAR)
- remote.nr = (struct sockaddr_nr *) to;
- else if (up->peername != NULLCHAR)
- remote.nr = (struct sockaddr_nr *) up->peername;
- else {
- errno = ENOTCONN;
- return -1;
- }
- /* The NETROM username is always ignored in outgoing traffic */
- nr_sendraw (remote.nr->nr_addr.node,
- (unsigned) (int) up->cb.rnr->protocol, (unsigned) (int) up->cb.rnr->protocol, bp);
- break;
- case TYPE_NETROML4:
- if ((cb.nr4 = up->cb.nr4) == NULLNR4CB) {
- free_p (bp);
- errno = ENOTCONN;
- return -1;
- }
- #ifdef notdef
- /* since I now fragment nr4 packets in send_nr4(),
- * don't worry, be happy :-) - WG7J
- */
- if (len_p (bp) > NR4MAXINFO) { /* reject big packets */
- free_p (bp);
- errno = EMSGSIZE;
- return -1;
- }
- #endif
- (void) send_nr4 (cb.nr4, bp);
-
- while ((cb.nr4 = up->cb.nr4) != NULLNR4CB &&
- cb.nr4->nbuffered >= cb.nr4->window) {
- if (up->noblock & SOCK_NOTXBLOCK) {
- errno = EWOULDBLOCK;
- return -1;
- } else if ((errno = kwait (up)) != 0) {
- errno = EINTR;
- return -1;
- }
- }
- if (cb.nr4 == NULLNR4CB) {
- errno = EBADF;
- return -1;
- }
- break;
- #endif
- default:
- break;
- }
- return cnt;
- }
-
-
-
- /* Return local name passed in an earlier bind() call */
- int
- getsockname (
- int s, /* Socket index */
- char *name, /* Place to stash name */
- int *namelen /* Length of same */
- ) {
- register struct usock *up;
-
- if ((up = itop (s)) == NULLUSOCK) {
- errno = EBADF;
- return -1;
- }
- if (name == NULLCHAR || namelen == (int *) NULL) {
- errno = EFAULT;
- return -1;
- }
- if (up->name == NULLCHAR) {
- /* Not bound yet */
- *namelen = 0;
- *name = 0;
- return 0;
- }
- if (up->name != NULLCHAR) {
- *namelen = min (*namelen, up->namelen);
- memcpy (name, up->name, (size_t) * namelen);
- }
- return 0;
- }
-
-
-
- /* Get remote name, returning result of earlier connect() call. */
- int
- getpeername (
- int s, /* Socket index */
- char *peername, /* Place to stash name */
- int *peernamelen /* Length of same */
- ) {
- register struct usock *up;
-
- if ((up = itop (s)) == NULLUSOCK) {
- errno = EBADF;
- return -1;
- }
- if (up->peername == NULLCHAR) {
- errno = ENOTCONN;
- return -1;
- }
- if (peername == NULLCHAR || peernamelen == (int *) NULL) {
- errno = EFAULT;
- return -1;
- }
- *peernamelen = min (*peernamelen, up->peernamelen);
- memcpy (peername, up->peername, (size_t) * peernamelen);
- return 0;
- }
-
-
-
- /* Return length of protocol queue, either send or receive. */
- int
- socklen (
- int s, /* Socket index */
- int rtx /* 0 = receive queue, 1 = transmit queue */
- ) {
- register struct usock *up;
- int len = -1;
-
- if ((up = itop (s)) == NULLUSOCK) {
- errno = EBADF;
- return -1;
- }
- if (up->cb.p == NULLCHAR) {
- errno = ENOTCONN;
- return -1;
- }
- if (rtx < 0 || rtx > 1) {
- errno = EINVAL;
- return -1;
- }
- switch (up->type) {
- case TYPE_LOCAL_DGRAM:
- switch (rtx) {
- case 0:
- len = len_q (up->cb.local->q);
- break;
- case 1:
- if (up->cb.local->peer != NULLUSOCK)
- len = len_q (up->cb.local->peer->cb.local->q);
- break;
- default:
- break;
- }
- break;
- case TYPE_LOCAL_STREAM:
- switch (rtx) {
- case 0:
- len = len_p (up->cb.local->q) + len_p (up->ibuf);
- break;
- case 1:
- if (up->cb.local->peer != NULLUSOCK)
- len = len_p (up->cb.local->peer->cb.local->q)
- + len_p (up->obuf);
- break;
- default:
- break;
- }
- break;
- case TYPE_TCP:
- switch (rtx) {
- case 0:
- len = up->cb.tcb->rcvcnt + len_p (up->ibuf);
- break;
- case 1:
- len = up->cb.tcb->sndcnt + len_p (up->obuf);
- break;
- default:
- break;
- }
- break;
- case TYPE_UDP:
- switch (rtx) {
- case 0:
- len = up->cb.udp->rcvcnt;
- break;
- case 1:
- len = 0;
- break;
- default:
- break;
- }
- break;
- #ifdef AX25
- case TYPE_AX25I:
- switch (rtx) {
- case 0:
- len = len_p (up->cb.ax25->rxq) + len_p (up->ibuf);
- break;
- case 1: /* Number of packets, not bytes */
- len = len_q (up->cb.ax25->txq);
- if (up->obuf != NULLBUF)
- len++;
- break;
- default:
- break;
- }
- break;
- #ifdef notdef
- case TYPE_AX25UI:
- switch (rtx) {
- case 0:
- len = len_q (Bcq);
- break;
- case 1:
- len = 0;
- break;
- default:
- break;
- }
- break;
- #endif /* notdef */
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- switch (rtx) {
- case 0:
- len = len_q (up->cb.rnr->rcvq);
- break;
- case 1:
- len = 0;
- break;
- default:
- break;
- }
- break;
- case TYPE_NETROML4:
- switch (rtx) {
- case 0:
- len = len_p (up->cb.nr4->rxq) + len_p (up->ibuf);
- break;
- case 1: /* Number of packets, not bytes */
- len = len_q (up->cb.nr4->txq);
- if (up->obuf != NULLBUF)
- len++;
- break;
- default:
- break;
- }
- break;
- #endif
- case TYPE_RAW:
- switch (rtx) {
- case 0:
- len = len_q (up->cb.rip->rcvq);
- break;
- case 1:
- len = 0;
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
- return len;
- }
-
-
-
- /* Force retransmission. Valid only for connection-oriented sockets. */
- int
- sockkick (
- int s /* Socket index */
- ) {
- register struct usock *up;
-
- if ((up = itop (s)) == NULLUSOCK) {
- errno = EBADF;
- return -1;
- }
- if (up->type == TYPE_LOCAL_STREAM || up->type == TYPE_LOCAL_DGRAM) {
- errno = EINVAL;
- return -1;
- }
- if (up->cb.p == NULLCHAR) {
- errno = ENOTCONN;
- return -1;
- }
- switch (up->type) {
- case TYPE_TCP:
- (void) kick_tcp (up->cb.tcb);
- break;
- #ifdef AX25
- case TYPE_AX25I:
- (void) kick_ax25 (up->cb.ax25);
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML4:
- (void) kick_nr4 (up->cb.nr4);
- break;
- #endif
- default:
- /* Datagram sockets can't be kicked */
- errno = EOPNOTSUPP;
- return -1;
- }
- return 0;
- }
-
-
-
- /* Change owner of socket, return previous owner */
- struct proc *
- sockowner (
- int s, /* Socket index */
- struct proc *newowner /* Process table address of new owner */
- ) {
- register struct usock *up;
- struct proc *pp;
-
- if ((up = itop (s)) == NULLUSOCK) {
- errno = EBADF;
- return NULLPROC;
- }
- pp = up->owner;
- if (newowner != NULLPROC)
- up->owner = newowner;
- return pp;
- }
-
-
-
- /* Close down a socket three ways. Type 0 means "no more receives"; this
- * replaces the incoming data upcall with a routine that discards further
- * data. Type 1 means "no more sends", and obviously corresponds to sending
- * a TCP FIN. Type 2 means "no more receives or sends". This I interpret
- * as "abort the connection".
- */
- int
- shutdown (
- int s, /* Socket index */
- int how /* (see above) */
- ) {
- register struct usock *up;
-
- if ((up = itop (s)) == NULLUSOCK) {
- errno = EBADF;
- return -1;
- }
- if (up->cb.p == NULLCHAR) {
- errno = ENOTCONN;
- return -1;
- }
- switch (up->type) {
- case TYPE_LOCAL_DGRAM:
- case TYPE_LOCAL_STREAM:
- if (up->cb.local->q == NULLBUF)
- close_s (s);
- else
- up->cb.local->flags = LOC_SHUTDOWN;
- break;
- case TYPE_TCP:
- switch (how) {
- case 0: /* No more receives -- replace upcall */
- up->cb.tcb->r_upcall = trdiscard;
- break;
- case 1: /* Send EOF */
- (void) close_tcp (up->cb.tcb);
- break;
- case 2: /* Blow away TCB */
- reset_tcp (up->cb.tcb);
- up->cb.tcb = NULLTCB;
- break;
- default:
- break;
- }
- break;
- #ifdef AX25
- #ifdef notdef
- case TYPE_AX25UI:
- close_s (s);
- break;
- #endif
- case TYPE_AX25I:
- switch (how) {
- case 0:
- case 1: /* Attempt regular disconnect */
- (void) disc_ax25 (up->cb.ax25);
- break;
- case 2: /* Blow it away */
- (void) reset_ax25 (up->cb.ax25);
- up->cb.ax25 = NULLAX25;
- break;
- default:
- break;
- }
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- close_s (s);
- break;
- case TYPE_NETROML4:
- switch (how) {
- case 0:
- case 1: /* Attempt regular disconnect */
- disc_nr4 (up->cb.nr4);
- break;
- case 2: /* Blow it away */
- reset_nr4 (up->cb.nr4);
- up->cb.nr4 = NULLNR4CB;
- break;
- default:
- break;
- }
- break;
- #endif
- case TYPE_RAW:
- case TYPE_UDP:
- close_s (s);
- break;
- default:
- errno = EOPNOTSUPP;
- return -1;
- }
- ksignal (up, 0);
- return 0;
- }
-
-
-
- /* Close a socket, freeing it for reuse. Try to do a graceful close on a
- * TCP socket, if possible
- */
- int
- close_s (
- int s /* Socket index */
- ) {
- register struct usock *up;
-
- if (s == -1)
- return 0;
- if ((up = itop (s)) == NULLUSOCK) {
- errno = EBADF;
- return -1;
- }
- if (--up->refcnt > 0)
- return 0; /* Others are still using it */
- usflush (s);
- if (up->ibuf != NULLBUF) {
- free_p (up->ibuf);
- up->ibuf = NULLBUF;
- }
- switch (up->type) {
- case TYPE_LOCAL_STREAM:
- case TYPE_LOCAL_DGRAM:
- if (up->cb.local->peer != NULLUSOCK) {
- up->cb.local->peer->cb.local->peer = NULLUSOCK;
- ksignal (up->cb.local->peer, 0);
- }
- free_q (&up->cb.local->q);
- free (up->cb.local);
- break;
- case TYPE_TCP:
- if (up->cb.tcb != NULLTCB) { /* In case it's been reset */
- up->cb.tcb->r_upcall = trdiscard;
- /* Tell the TCP_CLOSED upcall there's no more socket */
- up->cb.tcb->user = -1;
- if (up->cb.p) /* forget this for null sockets */
- (void) close_tcp (up->cb.tcb);
- }
- break;
- case TYPE_UDP:
- if (up->cb.udp != NULLUDP)
- (void) del_udp (up->cb.udp);
- break;
- #ifdef AX25
- case TYPE_AX25I:
- if (up->cb.ax25 != NULLAX25) {
- /* Tell the TCP_CLOSED upcall there's no more socket */
- up->cb.ax25->user = -1;
- (void) disc_ax25 (up->cb.ax25);
- }
- break;
- #ifdef notdef
- case TYPE_AX25UI:
- Axui_sock = -1;
- free_q (&Bcq);
- ksignal (&Bcq, 0); /* Unblock any reads */
- break;
- #endif /* notdef */
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- del_rnr (up->cb.rnr);
- break;
- case TYPE_NETROML4:
- if (up->cb.nr4 != NULLNR4CB) {
- /* Tell the TCP_CLOSED upcall there's no more socket */
- up->cb.nr4->user = -1;
- disc_nr4 (up->cb.nr4);
- }
- break;
- #endif
- case TYPE_RAW:
- del_ip (up->cb.rip);
- break;
- default:
- errno = EOPNOTSUPP;
- return -1;
- }
- #ifdef LZW
- if (up->zout != NULLLZW || up->zin != NULLLZW)
- lzwfree (up);
- #endif
- free (up->name);
- free (up->peername);
-
- up->cb.p = NULLCHAR;
- up->name = up->peername = NULLCHAR;
- up->type = NOTUSED;
- ksignal (up, 0); /* Wake up anybody doing an accept() or recv() */
- #ifdef LOOKSESSION
- if (up->look) /* Alert the process looking at us */
- alert (up->look, ENOTCONN);
- #endif
- return 0;
- }
-
-
-
- /* Increment reference count for specified socket */
- int
- usesock (int s)
- {
- struct usock *up;
-
- if ((up = itop (s)) == NULLUSOCK) {
- errno = EBADF;
- return -1;
- }
- up->refcnt++;
- return 0;
- }
-
-
-
- /* Blow away all sockets belonging to a certain process. Used by killproc(). */
- void
- freesock (struct proc *pp)
- {
- register struct usock *up;
- register int i;
-
- for (i = SOCKBASE; i < Nusock + SOCKBASE; i++) {
- up = itop (i);
- if (up != NULLUSOCK && up->type != NOTUSED && up->owner == pp)
- (void) shutdown (i, 2);
- }
- }
-
-
-
- /* Start of internal subroutines */
-
- /* Raw IP receive upcall routine */
- static void
- rip_recv (struct raw_ip *rp)
- {
- ksignal (itop (rp->user), 1);
- kwait (NULL);
- }
-
-
-
- /* UDP receive upcall routine */
- static void
- s_urcall (struct iface *iface OPTIONAL, struct udp_cb *udp, int16 cnt OPTIONAL)
- {
- ksignal (itop (udp->user), 1);
- kwait (NULL);
- }
-
-
-
- /* TCP receive upcall routine */
- static void
- s_trcall (struct tcb *tcb, int16 cnt OPTIONAL)
- {
- /* Wake up anybody waiting for data, and let them run */
- ksignal (itop (tcb->user), 1);
- kwait (NULL);
- }
-
-
-
- /* TCP transmit upcall routine */
- static void
- s_ttcall (struct tcb *tcb, int16 cnt OPTIONAL)
- {
- /* Wake up anybody waiting to send data, and let them run */
- ksignal (itop (tcb->user), 1);
- kwait (NULL);
- }
-
-
-
- /* TCP state change upcall routine */
- static void
- s_tscall (struct tcb *tcb, int old OPTIONAL, int new)
- {
- int s, ns;
- struct usock *up, *nup, *oup;
- union sp sp;
-
- s = tcb->user;
- oup = up = itop (s);
-
- switch (new) {
- case TCP_CLOSED:
- /* Clean up. If the user has already closed the socket,
- * then up will be null (s was set to -1 by the close routine).
- * If not, then this is an abnormal close (e.g., a reset)
- * and clearing out the pointer in the socket structure will
- * prevent any further operations on what will be a freed
- * control block. Also wake up anybody waiting on events
- * related to this tcb so they will notice it disappearing.
- */
- if (up != NULLUSOCK) {
- up->cb.tcb = NULLTCB;
- up->errcodes[0] = tcb->reason;
- up->errcodes[1] = tcb->type;
- up->errcodes[2] = tcb->code;
- }
- (void) del_tcp (tcb);
- break;
- case TCP_SYN_RECEIVED:
- /* Handle an incoming connection. If this is a server TCB,
- * then we're being handed a "clone" TCB and we need to
- * create a new socket structure for it. In either case,
- * find out who we're talking to and wake up the guy waiting
- * for the connection.
- */
- if (tcb->flags.clone) {
- /* Clone the socket */
- ns = socket (AF_INET, SOCK_STREAM, 0);
- nup = itop (ns);
- if (up == NULLUSOCK) /* shouldn't happen */
- return;
- if (nup == NULLUSOCK) {
- log (-1, "Couldn't open socket!\n");
- tcmdprintf ("Couldn't open socket!\n\007");
- return;
- }
- ASSIGN (*nup, *up);
- tcb->user = ns;
- nup->cb.tcb = tcb;
- /* Allocate new memory for the name areas */
- nup->name = mallocw (SOCKSIZE);
- nup->peername = mallocw (SOCKSIZE);
- /* Store the new socket # in the old one */
- up->rdysock = ns;
- up = nup;
- s = ns;
- } else {
- /* Allocate space for the peer's name */
- up->peername = mallocw (SOCKSIZE);
- /* Store the old socket # in the old socket */
- up->rdysock = s;
- }
- /* Load the addresses. Memory for the name has already
- * been allocated, either above or in the original bind.
- */
- sp.p = up->name;
- sp.in->sin_family = AF_INET;
- sp.in->sin_addr.s_addr = up->cb.tcb->conn.local.address;
- sp.in->sin_port = up->cb.tcb->conn.local.port;
- up->namelen = SOCKSIZE;
-
- sp.p = up->peername;
- sp.in->sin_family = AF_INET;
- sp.in->sin_addr.s_addr = up->cb.tcb->conn.remote.address;
- sp.in->sin_port = up->cb.tcb->conn.remote.port;
- up->peernamelen = SOCKSIZE;
-
- /* Wake up the guy accepting it, and let him run */
- ksignal (oup, 1);
- kwait (NULL);
- break;
- default: /* Ignore all other state transitions */
- break;
- }
- ksignal (up, 0); /* In case anybody's waiting */
- }
-
-
-
- /* Discard data received on a TCP connection. Used after a receive shutdown or
- * close_s until the TCB disappears.
- */
- static void
- trdiscard (struct tcb *tcb, int16 cnt)
- {
- struct mbuf *bp;
-
- (void) recv_tcp (tcb, &bp, (int16) cnt);
- free_p (bp);
- }
-
-
-
- #ifdef AX25
- /* AX.25 receive upcall */
- void
- s_arcall (struct ax25_cb *axp, int cnt OPTIONAL)
- {
- int ns;
- struct usock *up, *nup, *oup;
- union sp sp;
-
- up = itop (axp->user);
- /* When AX.25 data arrives for the first time the AX.25 listener
- is notified, if active. If the AX.25 listener is a server its
- socket is duplicated in the same manner as in s_tscall().
- */
- if (Axi_sock != -1 && axp->user == -1) {
- #if 1
- if (addreq (axp->local, axp->iface->ipcall))
- return;
- #endif
- oup = up = itop (Axi_sock);
- /* From now on, use the same upcalls as the listener */
- axp->t_upcall = up->cb.ax25->t_upcall;
- axp->r_upcall = up->cb.ax25->r_upcall;
- axp->s_upcall = up->cb.ax25->s_upcall;
- if (up->cb.ax25->flags.clone) {
- /* Clone the socket */
- ns = socket (AF_AX25, SOCK_STREAM, 0);
- nup = itop (ns);
- ASSIGN (*nup, *up);
- axp->user = ns;
- nup->cb.ax25 = axp;
- /* Allocate new memory for the name areas */
- nup->name = mallocw (sizeof (struct sockaddr_ax));
- nup->peername = mallocw (sizeof (struct sockaddr_ax));
-
- /* Store the new socket # in the old one */
- up->rdysock = ns;
- up = nup;
- } else {
- axp->user = Axi_sock;
- del_ax25 (up->cb.ax25);
- up->cb.ax25 = axp;
- /* Allocate space for the peer's name */
- up->peername = mallocw (sizeof (struct sockaddr_ax));
-
- /* Store the old socket # in the old socket */
- up->rdysock = Axi_sock;
- }
- /* Load the addresses. Memory for the name has already
- * been allocated, either above or in the original bind.
- */
- sp.p = up->name;
- sp.ax->sax_family = AF_AX25;
- memcpy (sp.ax->ax25_addr, axp->local, AXALEN);
- strncpy (sp.ax->iface, axp->iface->name, ILEN - 1);
- up->namelen = sizeof (struct sockaddr_ax);
-
- sp.p = up->peername;
- sp.ax->sax_family = AF_AX25;
- memcpy (sp.ax->ax25_addr, axp->remote, AXALEN);
- strncpy (sp.ax->iface, axp->iface->name, ILEN - 1);
- up->peernamelen = sizeof (struct sockaddr_ax);
-
- /* Wake up the guy accepting it, and let him run */
- ksignal (oup, 1);
- kwait (NULL);
- return;
- }
- /* Wake up anyone waiting, and let them run */
- ksignal (up, 1);
- kwait (NULL);
- }
-
-
-
- /* AX.25 transmit upcall */
- void
- s_atcall (struct ax25_cb *axp, int cnt OPTIONAL)
- {
- /* Wake up anyone waiting, and let them run */
- ksignal (itop (axp->user), 1);
- kwait (NULL);
- }
-
-
-
- /* AX25 state change upcall routine */
- void
- s_ascall (register struct ax25_cb *axp, int old OPTIONAL, int new)
- {
- int s;
- struct usock *up;
-
- s = axp->user;
- up = itop (s);
-
- switch (new) {
- case LAPB_DISCONNECTED:
- /* Clean up. If the user has already closed the socket,
- * then up will be null (s was set to -1 by the close routine).
- * If not, then this is an abnormal close (e.g., a reset)
- * and clearing out the pointer in the socket structure will
- * prevent any further operations on what will be a freed
- * control block. Also wake up anybody waiting on events
- * related to this block so they will notice it disappearing.
- */
- if (up != NULLUSOCK) {
- up->errcodes[0] = axp->reason;
- up->cb.ax25 = NULLAX25;
- }
- del_ax25 (axp);
- break;
- default: /* Other transitions are ignored */
- break;
- }
- ksignal (up, 0); /* In case anybody's waiting */
- }
- #endif
-
-
-
- #ifdef NETROM
- /* NET/ROM receive upcall routine */
- static void
- s_nrcall (struct nr4cb *cb, int16 cnt OPTIONAL)
- {
- /* Wake up anybody waiting for data, and let them run */
- ksignal (itop (cb->user), 1);
- kwait (NULL);
- }
-
-
-
- /* NET/ROM transmit upcall routine */
- static void
- s_ntcall (struct nr4cb *cb, int16 cnt OPTIONAL)
- {
- /* Wake up anybody waiting to send data, and let them run */
- /* ksignal(itop(cb->user),1); */
- /* Quick-fix for sending wait problem - Dave Perry, VE3IFB */
- ksignal (itop (cb->user), 0);
- kwait (NULL);
- }
-
-
-
- /* NET/ROM state change upcall routine */
- static void
- s_nscall (struct nr4cb *cb, int old, int new)
- {
- int s, ns;
- struct usock *up, *nup, *oup;
- union sp sp;
-
- s = cb->user;
- oup = up = itop (s);
-
- if (new == NR4STDISC && up != NULLUSOCK) {
- /* Clean up. If the user has already closed the socket,
- * then up will be null (s was set to -1 by the close routine).
- * If not, then this is an abnormal close (e.g., a reset)
- * and clearing out the pointer in the socket structure will
- * prevent any further operations on what will be a freed
- * control block. Also wake up anybody waiting on events
- * related to this cb so they will notice it disappearing.
- */
- up->cb.nr4 = NULLNR4CB;
- up->errcodes[0] = (char) cb->dreason;
- }
- if (new == NR4STCON && old == NR4STDISC) {
- /* Handle an incoming connection. If this is a server cb,
- * then we're being handed a "clone" cb and we need to
- * create a new socket structure for it. In either case,
- * find out who we're talking to and wake up the guy waiting
- * for the connection.
- */
- if (!up)
- return;
- if (cb->clone) {
- /* Clone the socket */
- ns = socket (AF_NETROM, SOCK_SEQPACKET, 0);
- nup = itop (ns);
- ASSIGN (*nup, *up);
- cb->user = ns;
- nup->cb.nr4 = cb;
- cb->clone = 0; /* to avoid getting here again */
- /* Allocate new memory for the name areas */
- nup->name = mallocw (sizeof (struct sockaddr_nr));
- nup->peername = mallocw (sizeof (struct sockaddr_nr));
-
- /* Store the new socket # in the old one */
- up->rdysock = ns;
- up = nup;
- s = ns;
- } else {
- /* Allocate space for the peer's name */
- up->peername = mallocw (sizeof (struct sockaddr_nr));
-
- /* Store the old socket # in the old socket */
- up->rdysock = s;
- }
- /* Load the addresses. Memory for the name has already
- * been allocated, either above or in the original bind.
- */
- sp.p = up->name;
- sp.nr->nr_family = AF_NETROM;
- ASSIGN (sp.nr->nr_addr, up->cb.nr4->local);
- up->namelen = sizeof (struct sockaddr_nr);
-
- sp.p = up->peername;
- sp.nr->nr_family = AF_NETROM;
- ASSIGN (sp.nr->nr_addr, up->cb.nr4->remote);
- up->peernamelen = sizeof (struct sockaddr_nr);
-
- /* Wake up the guy accepting it, and let him run */
- ksignal (oup, 1);
- kwait (NULL);
- }
- /* Ignore all other state transitions */
- ksignal (up, 0); /* In case anybody's waiting */
- }
- #endif
-
-
-
- /* Verify address family and length according to the socket type */
- static int
- checkaddr (int type, char *name, int namelen)
- {
- union sp sp;
-
- sp.p = name;
- /* Verify length and address family according to protocol */
- switch (type) {
- case TYPE_TCP:
- case TYPE_UDP:
- if (sp.in->sin_family != AF_INET || namelen != (int) sizeof (struct sockaddr_in))
- return -1;
- break;
- #ifdef AX25
- case TYPE_AX25I:
- #ifdef notdef
- case TYPE_AX25UI:
- #endif
- if (sp.ax->sax_family != AF_AX25 || namelen != (int) sizeof (struct sockaddr_ax))
- return -1;
- break;
- #endif
- #ifdef NETROM
- case TYPE_NETROML3:
- case TYPE_NETROML4:
- if (sp.nr->nr_family != AF_NETROM || namelen != (int) sizeof (struct sockaddr_nr))
- return -1;
- break;
- #endif
- default:
- break;
- }
- return 0;
- }
-
-
-
- /* Issue an automatic bind of a local address */
- static void
- autobind (int s, int af)
- {
- char buf[MAXSOCKSIZE];
- union sp sp;
-
- sp.p = buf;
- switch (af) {
- case AF_INET:
- sp.in->sin_family = AF_INET;
- sp.in->sin_addr.s_addr = INADDR_ANY;
- sp.in->sin_port = Lport++;
- (void) bind (s, sp.p, sizeof (struct sockaddr_in));
- break;
- #ifdef AX25
- case AF_AX25:
- sp.ax->sax_family = AF_AX25;
- memset (sp.ax->ax25_addr, '\0', AXALEN);
- memset (sp.ax->iface, '\0', ILEN);
- (void) bind (s, sp.p, sizeof (struct sockaddr_ax));
- break;
- #endif
- #ifdef NETROM
- case AF_NETROM:
- sp.nr->nr_family = AF_NETROM;
- memcpy (sp.nr->nr_addr.user, Mycall, AXALEN);
- memcpy (sp.nr->nr_addr.node, Mycall, AXALEN);
- (void) bind (s, sp.p, sizeof (struct sockaddr_nr));
- break;
- #endif
- default:
- break;
- }
- }
-
-
-
- unsigned short getnextport (void);
-
- unsigned short
- getnextport (void)
- {
- return (Lport++);
- }
-
-
-
- int
- socketalive (int s)
- {
- register struct usock *up;
-
- if ((up = itop (s)) == NULLUSOCK)
- return 0;
-
- if (!up->cb.p)
- return 0;
-
- if (up->cb.tcb == NULLTCB || up->cb.tcb->r_upcall == trdiscard)
- return 0;
-
- if (up->cb.local->peer->cb.local->peer == NULLUSOCK)
- return 0;
-
- return 1;
- }
-
-
- /* this is called by tipmail only ! - WG7J */
- #ifdef TIPMAIL
-
- /* Return a pair of mutually connected sockets in sv[0] and sv[1] */
- int
- socketpair (int af, int type, int protocol, int sv[])
- {
- struct usock *up0, *up1;
-
- if (sv == NULLINT) {
- errno = EFAULT;
- return -1;
- }
- if (af != AF_LOCAL) {
- errno = EAFNOSUPPORT;
- return -1;
- }
- if (type != SOCK_STREAM && type != SOCK_DGRAM) {
- errno = ESOCKTNOSUPPORT;
- return -1;
- }
- if ((sv[0] = socket (af, type, protocol)) == -1)
- return -1;
- if ((sv[1] = socket (af, type, protocol)) == -1) {
- close_s (sv[0]);
- return -1;
- }
- up0 = itop (sv[0]);
- up1 = itop (sv[1]);
- up0->cb.local->peer = up1;
- up1->cb.local->peer = up0;
- return sv[1];
- }
- #endif
-